package cn.chengpengper.seckill.stock.domain.service.impl;

import cn.chengpengper.seckill.common.code.HttpCode;
import cn.chengpengper.seckill.common.constants.SeckillConstants;
import cn.chengpengper.seckill.common.exception.SeckillException;
import cn.chengpengper.seckill.common.model.enums.SeckillStockBucketStatus;
import cn.chengpengper.seckill.mq.MessageSenderService;
import cn.chengpengper.seckill.stock.domain.event.SeckillStockBucketEvent;
import cn.chengpengper.seckill.stock.domain.model.dto.SeckillStockBucketDeduction;
import cn.chengpengper.seckill.stock.domain.model.entity.SeckillStockBucket;
import cn.chengpengper.seckill.stock.domain.model.enums.SeckillStockBucketEventType;
import cn.chengpengper.seckill.stock.domain.repository.SeckillStockBucketRepository;
import cn.chengpengper.seckill.stock.domain.service.SeckillStockBucketDomainService;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * @author chengpeng.hu
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SeckillStockBucketDomainServiceImpl implements SeckillStockBucketDomainService {

    private final SeckillStockBucketRepository seckillStockBucketRepository;

    private final MessageSenderService messageSenderService;

    @Value("${message.mq.type}")
    private String eventType;

    @Override
    public boolean suspendBuckets(Long goodsId) {
        log.info("suspendBuckets|禁用库存分桶|{}", goodsId);
        if (goodsId == null || goodsId <= 0) {
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        boolean success = seckillStockBucketRepository.suspendBuckets(goodsId);
        if(!success){
            return false;
        }
        SeckillStockBucketEvent bucketEvent = new SeckillStockBucketEvent(goodsId, SeckillStockBucketStatus.DISABLED.getCode(), getTopicEvent());
        messageSenderService.send(bucketEvent);
        log.info("suspendBuckets|库存分桶已禁用|{}", goodsId);
        return true;
    }

    @Override
    public boolean resumeBuckets(Long goodsId) {
        log.info("resumeBuckets|启用库存分桶|{}", goodsId);
        if (goodsId == null || goodsId <= 0){
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        boolean success = seckillStockBucketRepository.resumeBuckets(goodsId);
        if (!success){
            return false;
        }
        SeckillStockBucketEvent seckillStockBucketEvent = new SeckillStockBucketEvent(goodsId, SeckillStockBucketEventType.ENABLED.getCode(), getTopicEvent());
        messageSenderService.send(seckillStockBucketEvent);
        log.info("resumeBuckets|库存分桶已启用|{}", goodsId);
        return true;
    }

    @Override
    public List<SeckillStockBucket> getBucketsByGoodsId(Long goodsId) {
        if (goodsId == null || goodsId <= 0){
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        return seckillStockBucketRepository.getBucketsByGoodsId(goodsId);
    }

    @Override
    public boolean arrangeBuckets(Long goodsId, List<SeckillStockBucket> buckets) {
        log.info("arrangeBuckets|编排库存分桶|{}",goodsId);
        if(Objects.isNull(goodsId) || goodsId <= 0 || CollectionUtils.isEmpty(buckets)){
            log.error("arrangeBuckets|编排库存分桶参数错误|{}",goodsId);
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        // 交易数据
        this.checkBuckets(goodsId,buckets);
        //存储分桶数据
        boolean success = seckillStockBucketRepository.submitBuckets(goodsId, buckets);
        if(!success){
            return false;
        }
        SeckillStockBucketEvent seckillStockBucketEvent = new SeckillStockBucketEvent(goodsId, SeckillStockBucketEventType.ARRANGED.getCode(), getTopicEvent());
        messageSenderService.send(seckillStockBucketEvent);
        log.info("arrangeBuckets|编排库存分桶已完成|{}",goodsId);
        return true;
    }

    private void checkBuckets(Long goodsId, List<SeckillStockBucket> buckets){
        //校验数据
        buckets.forEach((bucket) -> {
            if (!goodsId.equals(bucket.getGoodsId())){
                throw new SeckillException(HttpCode.BUCKET_GOODSID_ERROR);
            }
            if (bucket.getInitialStock() == null || bucket.getInitialStock() < 0){
                throw new SeckillException(HttpCode.BUCKET_INIT_STOCK_ERROR);
            }
            if (bucket.getAvailableStock() == null || bucket.getInitialStock() < 0){
                throw new SeckillException(HttpCode.BUCKET_AVAILABLE_STOCK_ERROR);
            }
            if (bucket.getInitialStock() < bucket.getAvailableStock()){
                throw new SeckillException(HttpCode.BUCKET_STOCK_ERROR);
            }
        });
    }

    @Override
    public boolean decreaseStock(SeckillStockBucketDeduction stockDeduction) {
        log.info("decreaseItemStock|扣减库存|{}", JSON.toJSONString(stockDeduction));
        if (stockDeduction == null || stockDeduction.isEmpty()){
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        return seckillStockBucketRepository.decreaseStock(stockDeduction.getQuantity(), stockDeduction.getSerialNo(), stockDeduction.getGoodsId());
    }

    @Override
    public boolean increaseStock(SeckillStockBucketDeduction stockDeduction) {
        log.info("increaseItemStock|增加库存|{}", JSON.toJSONString(stockDeduction));
        if (stockDeduction == null || stockDeduction.isEmpty()){
            throw new SeckillException(HttpCode.PARAMS_INVALID);
        }
        return seckillStockBucketRepository.increaseStock(stockDeduction.getQuantity(), stockDeduction.getSerialNo(), stockDeduction.getGoodsId());
    }

    /**
     * 获取主题事件
     */
    private String getTopicEvent() {
        return SeckillConstants.EVENT_PUBLISH_TYPE_ROCKETMQ.equals(eventType) ? SeckillConstants.TOPIC_EVENT_ROCKETMQ_STOCK : SeckillConstants.TOPIC_EVENT_COLA;
    }

}
